import * as Cesium from "cesium"
import { cartesian3ToDegreesHeight } from "./utils"

class DrawTool {
  //1.定义绘图类型
  DrawTypes = {
    Polyline: "Polyline",
    Point: "Point",
    Polygon: "Polygon",
  }

  // 2. 初始化绘图工具(即构建一个绘图工具对象,这个对象包含类里面定义的所有方法)
  constructor(viewer) {
    // 保存viewer实例
    this.viewer = viewer
    // 创建鼠标事件处理器
    this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
    // 创建绘制结束事件
    this.DrawEndEvent = new Cesium.Event()
    // 初始化点数组
    this.points = []
    // 阻止默认右键菜单
    this.viewer.scene.canvas.addEventListener("contextmenu", (e) => {
      if (this.drawEntity) {
        e.preventDefault()
      }
    })
  }

  //3.激活绘制工具
  active(drawType) {
    //检查是否是有效的绘图类型
    if (Object.keys(this.DrawTypes).includes(drawType)) {
      this.drawType = drawType
      this.positions = []
      this.curPositions = []

      this.registerEvents()
      this.createMarker(drawType)
    }
  }

  //4.创建提示标记
  createMarker(drawType) {
    this.marker = document.createElement("div")
    this.marker.innerHTML = `左键点击绘制${drawType},右键结束绘制`
    this.marker.className = "marker-draw"
    this.viewer.cesiumWidget.container.appendChild(this.marker)
  }

  //5.注册所有事件
  registerEvents() {
    this.leftClickEvent()
    this.rightClickEvent()
    this.mouseMoveEvent()
  }

  // 6.坐标转换 - 屏幕坐标转笛卡尔坐标
  positionTransfer(position) {
    return (
      this.viewer.scene.pickPosition(position) ||
      this.viewer.scene.camera.pickEllipsoid(
        position,
        this.viewer.scene.globe.ellipsoid
      )
    )
  }

  // 7.鼠标移动事件 - 更新绘制状态
  mouseMoveEvent() {
    this.handler.setInputAction((e) => {
      this.marker.style.left = e.endPosition.x + 20 + "px"
      this.marker.style.top = e.endPosition.y - 20 + "px"
      let position = this.positionTransfer(e.endPosition)
      if (!position || !this.drawEntity) return
      this.curPositions = [...this.positions, position]
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
  }

  //8.左键点击事件 - 添加绘制点
  leftClickEvent() {
    this.handler.setInputAction((e) => {
      // 获取点击位置
      let position = this.positionTransfer(e.position)
      if (!position) return
      // 存储绘制点
      this.positions.push(position)
      this.curPositions.push(position)
      // 点击第一个点，开始绘制
      if (this.positions.length === 1) {
        this.startDraw()
      }
      // 如果绘制类型是点，生成点实体
      if (this.drawType === this.DrawTypes.Point) {
        this.generatePoint(position)
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
  }

  // 9.开始绘制
  startDraw() {
    switch (this.drawType) {
      case this.DrawTypes.Point:
        this.drawEntity = this.generatePoint(this.positions[0])
        this.minPositionCount = 1
        break
      case this.DrawTypes.Polyline:
        this.generatePolyline()
        this.minPositionCount = 2
        break
      case this.DrawTypes.Polygon:
        this.generatePolygon()
        this.minPositionCount = 3
        break
    }
  }

  // 生成点实体
  generatePoint(position) {
    //创建点实体
    const pointEntity = this.viewer.entities.add({
      //设置点的位置
      position: position,
      //设置点的样式
      point: {
        pixelSize: 12,
        color: Cesium.Color.RED,
        outlineColor: Cesium.Color.WHITE,
        outlineWidth: 2,
        heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, // 改为相对高度
        disableDepthTestDistance: Number.POSITIVE_INFINITY, // 确保点始终可见
      },
      //设置点的标签
      label: {
        text: `点 ${this.positions.length}`,
        font: "14px sans-serif",
        fillColor: Cesium.Color.WHITE,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 2,
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        pixelOffset: new Cesium.Cartesian2(0, -10),
        heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND, // 改为相对高度
        disableDepthTestDistance: Number.POSITIVE_INFINITY, // 确保标签始终可见
      },
    })
    //保存点实体
    this.points.push(pointEntity)
    //返回点实体
    return pointEntity
  }

  // 生成线实体
  generatePolyline() {
    // 创建线实体
    this.drawEntity = this.viewer.entities.add({
      // 设置实体类型
      Type: this.DrawTypes.Polyline,
      // 设置线的属性
      polyline: {
        // 使用 CallbackProperty 动态更新线的位置
        positions: new Cesium.CallbackProperty((e) => {
          return this.curPositions
        }, false),
        width: 3,
        material: new Cesium.PolylineGlowMaterialProperty({
          glowPower: 0.2,
          color: Cesium.Color.YELLOW,
        }),
        // 让线贴在地面上
        clampToGround: true,
      },
    })
  }

  // 生成面实体
  generatePolygon() {
    this.drawEntity = this.viewer.entities.add({
      //  设置实体类型为多边形
      Type: this.DrawTypes.Polygon,
      // 设置多边形的面
      polygon: {
        hierarchy: new Cesium.CallbackProperty((e) => {
          // 将当前所有点连接起来，并闭合（连接首尾点）
          return new Cesium.PolygonHierarchy(
            this.curPositions.concat(this.curPositions[0])
          )
        }, false),
        material: Cesium.Color.RED.withAlpha(0.6),
        classificationType: Cesium.ClassificationType.BOTH,
      },
      // 设置多边形的边框线
      polyline: {
        positions: new Cesium.CallbackProperty((e) => {
          return this.curPositions.concat(this.curPositions[0])
        }, false),
        width: 1,
        // 设置边框线材质 - 虚线
        material: new Cesium.PolylineDashMaterialProperty({
          color: Cesium.Color.YELLOW,
        }),
        clampToGround: true,
      },
    })
  }

  //10.右键点击事件 - 结束绘制
  rightClickEvent() {
    this.handler.setInputAction(() => {
      // 根据绘制类型更新绘制实体
      switch (this.drawType) {
        case this.DrawTypes.Polyline:
          // 更新线实体的位置
          this.drawEntity.polyline.positions = this.positions
          break
        case this.DrawTypes.Polygon:
          // 设置面的最终形状
          this.drawEntity.polygon.hierarchy = new Cesium.PolygonHierarchy(
            this.positions.concat(this.positions[0])
          )
          this.drawEntity.polyline.positions = this.positions.concat(
            this.positions[0]
          )
          break
      }
      // 结束绘制
      this.deactive()
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
  }

  // 11.销毁提示标记
  destoryMarker() {
    this.marker && this.viewer.cesiumWidget.container.removeChild(this.marker)
    this.marker = null
  }

  // 12.注销所有事件
  unRegisterEvents() {
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
    this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
  }

  //  13.结束绘制
  deactive() {
    // 触发绘制结束事件
    this.DrawEndEvent.raiseEvent(this.drawEntity, this.positions)
    // 注销所有事件
    this.unRegisterEvents()
    // 销毁提示标记
    this.destoryMarker()
    // 重置绘制类型
    this.drawType = undefined
    // 重置绘制实体
    this.drawEntity = undefined
    // 重置绘制点
    this.positions = []
    // 重置当前绘制点
    this.curPositions = []
  }
}

export default DrawTool
